#include <stdio.h>
#ifdef WIN32
#include <winsock2.h>
#include <Ws2tcpip.h>
#endif
#include <cstring>
#include "pcapParse.h"

#ifdef WIN32
#pragma comment(lib,"ws2_32.lib")
typedef int socklen_t;

#else

#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>

#include <unistd.h>
#include <fcntl.h>


#define SOCKET int32_t
#define SOCKET_ERROR   (-1)
#define INVALID_SOCKET (-1)

#endif
#ifndef WIN32

int closesocket(int sock)
{
    (void)shutdown(sock, SHUT_RDWR);
    return close(sock);
}

#endif


using std::shared_ptr;
using std::make_shared;




enum {
    kRtcpExpectedVersion = 2,
    kRtcpMinHeaderLength = 4,
    kRtcpMinParseLength = 8,

    kRtpExpectedVersion = 2,
    kRtpMinParseLength = 12
};

// webRtc的公共库


bool rtpParse(RTPHeader& header, const void *p, size_t sizeLen)
{
    const uint8_t* const _ptrRTPDataBegin = (const uint8_t* const)p;
    const uint8_t* const _ptrRTPDataEnd = _ptrRTPDataBegin + sizeLen;
    const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
    if (length < kRtpMinParseLength) {
        return false;
    }

    // Version
    const uint8_t V = _ptrRTPDataBegin[0] >> 6;
    // Padding
    const bool          P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
    // eXtension
    const bool          X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
    const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f;
    const bool          M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;

    const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f;

    const uint16_t sequenceNumber = (_ptrRTPDataBegin[2] << 8) +
        _ptrRTPDataBegin[3];

    const uint8_t* ptr = &_ptrRTPDataBegin[4];

    uint32_t RTPTimestamp = *ptr++ << 24;
    RTPTimestamp += *ptr++ << 16;
    RTPTimestamp += *ptr++ << 8;
    RTPTimestamp += *ptr++;

    uint32_t SSRC = *ptr++ << 24;
    SSRC += *ptr++ << 16;
    SSRC += *ptr++ << 8;
    SSRC += *ptr++;

    if (V != kRtpExpectedVersion) {
        printf("V:%d is invalid.\n", V);
        return false;
    }

    const uint8_t CSRCocts = CC * 4;

    if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
        printf("!!!! ptr:%p, CSRCocts:%d, _ptrRTPDataEnd:%p is invalid.\n", ptr, CSRCocts, _ptrRTPDataEnd);
        return false;
    }

    header.markerBit = M;
    header.payloadType = PT;
    header.sequenceNumber = sequenceNumber;
    header.timestamp = RTPTimestamp;
    header.ssrc = SSRC;
    header.numCSRCs = CC;
    header.paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0;

    for (unsigned int i = 0; i < CC; ++i) {
        uint32_t CSRC = *ptr++ << 24;
        CSRC += *ptr++ << 16;
        CSRC += *ptr++ << 8;
        CSRC += *ptr++;
        header.arrOfCSRCs[i] = CSRC;
    }

    header.headerLength = 12 + CSRCocts;

    // If in effect, MAY be omitted for those packets for which the offset
    // is zero.
    header.extension.hasTransmissionTimeOffset = false;
    header.extension.transmissionTimeOffset = 0;

    // May not be present in packet.
    header.extension.hasAbsoluteSendTime = false;
    header.extension.absoluteSendTime = 0;

    // May not be present in packet.
    header.extension.hasAudioLevel = false;
    header.extension.audioLevel = 0;

    if (X) {
        /* RTP header extension, RFC 3550.
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |      defined by profile       |           length              |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                        header extension                       |
        |                             ....                              |
        */
        const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
        if (remain < 4) {
            printf("remain:%d is invalid.\n", remain);
            return false;
        }

        header.headerLength += 4;

        uint16_t definedByProfile = *ptr++ << 8;
        definedByProfile += *ptr++;

        uint16_t XLen = *ptr++ << 8;
        XLen += *ptr++; // in 32 bit words
        XLen *= 4; // in octs

        if (remain < (4 + XLen)) {
            printf("remain:%d XLen:%d is definedByProfile:%d, invalid.\n", remain, XLen, definedByProfile);
            return false;
        }
        header.headerLength += XLen;
    }
    return true;
}

CPcapParse::CPcapParse()
{
    m_fp = NULL;
}

CPcapParse::~CPcapParse()
{
    reset();
}

#define  PCAP_FILE_MAGIC_1   0Xd4
#define  PCAP_FILE_MAGIC_2   0Xc3
#define  PCAP_FILE_MAGIC_3   0Xb2
#define  PCAP_FILE_MAGIC_4   0Xa1

int CPcapParse::init(const char *pchPcapFile)
{
    int ret = 0;

    if (!pchPcapFile)
    {
        return -1;
    }
    m_fp = fopen(pchPcapFile, "rb+");
    if (!m_fp)
    {
        return -2;
    }
    fread(&m_FileHeader, 1, sizeof(m_FileHeader), m_fp);
    if (m_FileHeader.magic[0] != PCAP_FILE_MAGIC_1 || m_FileHeader.magic[1] != PCAP_FILE_MAGIC_2 ||
        m_FileHeader.magic[2] != PCAP_FILE_MAGIC_3 || m_FileHeader.magic[3] != PCAP_FILE_MAGIC_4)
    {
        printf("The file is not a pcap file.\n");
        
        return -3;
    }

	switch (m_FileHeader.linktype)
	{
		// windows loop back
	case 0:
        m_sizePktOffset = 32;
		break;
	case 1:
        m_sizePktOffset = 42;
		break;
		// ios/mac
	case 101:
        m_sizePktOffset = 28;
		break;
    case 276:
        m_sizePktOffset = 48;
        break;
	default:
        m_sizePktOffset = 44;
		break;
	}

    printf("CPcapParse::init m_sizePktOffset:%d \n", m_sizePktOffset);
    return ret;
}

int CPcapParse::copyPktData(char *pchData, size_t bufLen, size_t &dataLen, uint64_t *pMs)
{
    size_t ret;
    pcapPkthdr_t  packetHeader;
    size_t readLen;
    char buf[1500];

    ret = fread(&packetHeader, sizeof(packetHeader), 1, m_fp);
    if (pMs)
    {
        *pMs = packetHeader.u_seconds / 1000;
        *pMs = *pMs + (packetHeader.seconds * 1000);
    }

    fseek(m_fp, m_sizePktOffset, SEEK_CUR);

    readLen = packetHeader.caplen - m_sizePktOffset;
    dataLen = fread(pchData, 1, readLen, m_fp);

    if (dataLen != readLen)
    {
        return -1;
    }

    return 0;
}

void CPcapParse::reset()
{
    if (m_fp)
    {
        fclose(m_fp);
        m_fp = NULL;
    }
    m_sizePktOffset = 0;
}

rtpPacket::rtpPacket()
{
    m_len = 0;
    m_ts = 0;
}

rtpPacket::~rtpPacket()
{

}

int rtpPacket::init(const char *pchBuf, size_t sizeLen, uint64_t ts)
{
    if (sizeLen > sizeof(m_buf))
    {
        return -1;
    }
    else
    {
        memcpy(m_buf, pchBuf, sizeLen);
        m_len = sizeLen;
        m_ts = ts;
    }

    return 0;
}

CRtpManage::CRtpManage()
{
    memset(m_inFile, 0, sizeof(m_inFile));

#ifdef _WIN32
	WORD wVersionRequested = MAKEWORD(2, 2);
	WSADATA wsaData;
	WSAStartup(wVersionRequested, &wsaData);
#endif
}

CRtpManage::~CRtpManage()
{
#ifdef _WIN32

    WSACleanup();

#endif
}

int CRtpManage::init(const char *inFile)
{
    int ret = 0;

    sprintf(m_inFile, "%s", inFile);

    if (m_pcap.init(inFile))
    {
        return -111;
    }

    ret = proc();
 
    return ret;
}

#include <chrono>

static long long getCurrentMs()
{
	auto time_now = std::chrono::system_clock::now();
	auto duration_in_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_now.time_since_epoch());

	return duration_in_ms.count();
}

static bool is_ipv4(const char* host) {
	struct in_addr addr;
	return 1 == inet_pton(AF_INET, host, &addr);
}

static bool is_ipv6(const char* host) {
	struct in6_addr addr;
	return 1 == inet_pton(AF_INET6, host, &addr);
}

static struct sockaddr_storage make_sockaddr(const char* host, uint16_t port) {
	struct sockaddr_storage storage;
	memset(&storage, 0, sizeof(storage));

	struct in_addr addr;
	struct in6_addr addr6;
	if (1 == inet_pton(AF_INET, host, &addr)) {
		// host是ipv4
		reinterpret_cast<struct sockaddr_in&>(storage).sin_addr = addr;
		reinterpret_cast<struct sockaddr_in&>(storage).sin_family = AF_INET;
		reinterpret_cast<struct sockaddr_in&>(storage).sin_port = htons(port);
		return storage;
	}
	if (1 == inet_pton(AF_INET6, host, &addr6)) {
		// host是ipv6
		reinterpret_cast<struct sockaddr_in6&>(storage).sin6_addr = addr6;
		reinterpret_cast<struct sockaddr_in6&>(storage).sin6_family = AF_INET6;
		reinterpret_cast<struct sockaddr_in6&>(storage).sin6_port = htons(port);
		return storage;
	}
    return storage;
}

int CRtpManage::netPlay(const int8_t * remoteAddr, uint16_t remotePort, uint16_t localPort)
{

    struct sockaddr_storage m_remoteAddr = make_sockaddr((const char *)remoteAddr, remotePort);

    SOCKET m_socket;

#if 0
	memset(&m_remoteAddr, 0, sizeof(struct sockaddr_in));
	m_remoteAddr.sin_family = AF_INET;
	m_remoteAddr.sin_port = htons(remotePort);
	m_remoteAddr.sin_addr.s_addr = inet_addr((const char*)remoteAddr);
#endif

    bool bIsV4 = true;
    if (is_ipv6((const char*)remoteAddr))
    {
        bIsV4 = false;
    }

    if (bIsV4)
    {
		struct sockaddr_in locateAddr;
		locateAddr.sin_family = AF_INET;
		//locateAddr.sin_port = htons(localPort);
		locateAddr.sin_addr.s_addr = htonl(INADDR_ANY);

		if ((m_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		{
			return -1;
		}
		if (bind(m_socket, (struct sockaddr*)&locateAddr, sizeof(sockaddr_in)) < 0)
		{

			return -1;
		}
    }
    else
    {

		if ((m_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		{
			return -1;
		}


		struct sockaddr_in6 locateAddr;
		memset(&locateAddr, 0, sizeof(sockaddr_in6));
		locateAddr.sin6_family = AF_INET6;
		//locateAddr.sin6_port = htons(localPort);
		locateAddr.sin6_addr = IN6ADDR_ANY_INIT;
		if (bind(m_socket, (struct sockaddr*)&locateAddr, sizeof(sockaddr_in6)) < 0)
		{
			return -1;
		}
    }
	

    int iRet = 0;
    uint64_t ms = 0;
    uint64_t lastms = 0;

    long long t_sender_use = 0;
    std::list<shared_ptr<rtpPacket>>::iterator it = m_listRtp.begin();
    int k = 0;
    do 
    {
       
		shared_ptr<rtpPacket> pkt = *it;
		ms = pkt->getTs();

		int nServAddLen = sizeof(m_remoteAddr);
	
		if (lastms != 0)
		{
            int64_t t_wait = ms - lastms - t_sender_use;

            printf("t_wait:%lld ms:%llu lastmu:%llu t_sender_use:%lld k:%d \n", t_wait, ms, lastms, t_sender_use, k );
            k++;
            
			if (t_wait > 0)
			{
#ifdef WIN32
				Sleep(t_wait);
#else

				usleep((t_wait) * 1000);
#endif
				lastms = ms;
			}
		}
		// 首次执行
		else
		{
			lastms = ms;
		}

        long long t_1 =  getCurrentMs();
		iRet = sendto(m_socket, pkt->getHeader(), pkt->getPktLen(), 0, (sockaddr*)&m_remoteAddr, nServAddLen);
		if (iRet == SOCKET_ERROR) {
			printf("sendto() failed:\n");
			break;
		}
        long long t_2 = getCurrentMs();
        t_sender_use = t_2 - t_1;


        it++;
    } while (it != m_listRtp.end());

    closesocket(m_socket);

    return 0;
}


int CRtpManage::proc()
{
    char buf[2000];
    size_t sizeLen;
    RTPHeader rtpHeader;
    //unsigned short seq = 0;
    unsigned int seq = 0;
    unsigned int seqRound = 1;
    unsigned int addCount = 0;
    bool bBegin = true;
    const unsigned int maxInOrder = 5000;

    // 将所有的pcap包读取到内存的map中，过滤ssrc的问题由wireshark完成，本程序不做处理

    uint64_t t_ts = 0;
    while (!m_pcap.copyPktData(buf, sizeof(buf), sizeLen, &t_ts))
    {
        

        shared_ptr<rtpPacket> pPkt = make_shared<rtpPacket>();
        if (pPkt->init(buf, sizeLen, t_ts))
        {
            continue;
        }
        m_listRtp.push_back(pPkt);

        if (!rtpParse(rtpHeader, buf, sizeLen))
        {
            printf("Parse failed.\n");
            continue;
        }
        if (bBegin)
        {
            seq = rtpHeader.sequenceNumber;
            seqRound = 0;
            bBegin = false;
        }
        else
        {
            if (seq > (unsigned int)(rtpHeader.sequenceNumber) + maxInOrder + seqRound * 65536)
            {
                addCount++;
            }
            if (addCount > 1000)
            {
                addCount = 0;
                seqRound++;
                seq = seqRound * 65536 + rtpHeader.sequenceNumber;
            }

            if (seq + 1 == seqRound * 65536 + rtpHeader.sequenceNumber)
            {
                seq = seqRound * 65536 + rtpHeader.sequenceNumber;
            }
            else if (seq + maxInOrder < seqRound * 65536 + rtpHeader.sequenceNumber)
            {
                seq = seqRound * 65536 + rtpHeader.sequenceNumber;
            }
        }
        if (rtpHeader.sequenceNumber < maxInOrder && addCount > 0)
        {
            m_mapRtp[(seqRound + 1) * 65536 + rtpHeader.sequenceNumber] = pPkt;
        }
        else
        {
            m_mapRtp[seqRound * 65536 + rtpHeader.sequenceNumber] = pPkt;
        }
        
        
    }
   return 0;
}


void CRtpManage::reset()
{
    m_pcap.reset();
    m_mapRtp.clear();
    m_listRtp.clear();
}
void CRtpManage::getMap(map<unsigned int, shared_ptr<rtpPacket> >& omapRtp)
{
    omapRtp = m_mapRtp;
}
void CRtpManage::getList(std::list<shared_ptr<rtpPacket> >& olistRtp)
{
    olistRtp = m_listRtp;
}



